1 module hip.game2d.ninepatch; 2 public import hip.api.renderer.texture; 3 public import hip.game2d.sprite; 4 import hip.game2d.renderer_data; 5 6 enum NinePatchType 7 { 8 SCALED, 9 TILED //I Think this effect is quite ugly, but maybe it'll be useful at some time 10 } 11 12 class NinePatch 13 { 14 uint width, height; 15 float x, y; 16 float scaleX, scaleY; 17 protected HipSprite[9] sprites; 18 protected HipSpriteVertex[9*4] vertices; 19 IHipTexture texture; 20 NinePatchType stretchStrategy; 21 22 this(uint width, uint height, IHipTexture tex, NinePatchType type = NinePatchType.SCALED) 23 { 24 this.width = width; 25 this.height = height; 26 x = y = 0; 27 scaleX = scaleY = 1; 28 texture = tex; 29 stretchStrategy = type; 30 for(int i = 0; i < 9; i++) 31 sprites[i] = new HipSprite(tex); 32 33 setTextureRegions(); 34 setSize(width, height); 35 } 36 37 void setSize(int width, int height) 38 { 39 this.width = width; 40 this.height = height; 41 build(); 42 } 43 44 /** 45 * The arguments will be divided by the texture width and height for 46 * generating the UVs 47 */ 48 void setTextureRegions(uint x, uint y, uint width, uint height) 49 { 50 int texWidth = sprites[0].getTextureWidth; 51 int texHeight = sprites[0].getTextureHeight; 52 53 float tx = cast(float)x/texWidth; 54 float ty = cast(float)y/texHeight; 55 56 float xw = (cast(float)width/3.0f)/texWidth; 57 float yh = (cast(float)height/3.0f)/texHeight; 58 float xw2 = xw*2; 59 float xw3 = xw*3; 60 float yh2 = yh*2; 61 float yh3 = yh*3; 62 63 sprites[TOP_LEFT].setRegion (tx+0, ty+0, tx+xw, ty+yh); 64 sprites[TOP_MID].setRegion (tx+xw, ty+0, tx+xw2, ty+yh); 65 sprites[TOP_RIGHT].setRegion(tx+xw2, ty+0, tx+xw3, ty+yh); 66 67 sprites[MID_LEFT].setRegion (tx+0, ty+yh, tx+xw, ty+yh2); 68 sprites[MID_MID].setRegion (tx+xw, ty+ yh,tx+ xw2,ty+ yh2); 69 sprites[MID_RIGHT].setRegion(tx+xw2,ty+ yh,tx+ xw3,ty+ yh2); 70 71 sprites[BOT_LEFT].setRegion (tx+0, ty+yh2, tx+xw, ty+yh3); 72 sprites[BOT_MID].setRegion (tx+xw, ty+ yh2,tx+ xw2,ty+ yh3); 73 sprites[BOT_RIGHT].setRegion(tx+xw2,ty+ yh2,tx+ xw3,ty+ yh3); 74 } 75 76 /** 77 * Cuts the entire image in 9 slices 78 */ 79 void setTextureRegions() 80 { 81 setTextureRegions(0, 0, sprites[0].getTextureWidth, sprites[0].getTextureHeight); 82 } 83 84 void build() 85 { 86 float xScalingFactor = cast(float)(width - cast(float)(sprites[TOP_LEFT].width*2)); 87 if(sprites[TOP_LEFT].width != 0) 88 xScalingFactor/= cast(float)sprites[TOP_LEFT].width; 89 else 90 xScalingFactor = 0; 91 92 float yScalingFactor = cast(float)height - cast(float)(sprites[TOP_LEFT].height*2); 93 if(sprites[TOP_LEFT].height != 0) 94 yScalingFactor/= cast(float)sprites[TOP_LEFT].height; 95 else 96 yScalingFactor = 0; 97 98 if(xScalingFactor < 1) xScalingFactor = 1; 99 if(yScalingFactor < 1) yScalingFactor = 1; 100 101 102 int spWidth = sprites[TOP_LEFT].width; 103 int spHeight = sprites[TOP_LEFT].height; 104 105 int px2 = width-spWidth; 106 if(px2 < spWidth) px2 = spWidth; 107 108 int py2 = height-spHeight; 109 if(py2 < spHeight) py2 = spHeight; 110 111 112 //First, take care of those which don't scale. 113 sprites[TOP_LEFT].setPosition(x, y); 114 sprites[TOP_RIGHT].setPosition(x + px2, y); 115 sprites[BOT_LEFT].setPosition(x, y + py2); 116 sprites[BOT_RIGHT].setPosition(x + px2, y + py2); 117 118 //Now, those which scales in only one direction 119 sprites[TOP_MID].setPosition(x+spWidth, y); 120 sprites[MID_LEFT].setPosition(x, y+spHeight); 121 sprites[MID_RIGHT].setPosition(x+ px2, y+spHeight); 122 sprites[BOT_MID].setPosition(x+spWidth, y + py2); 123 sprites[MID_MID].setPosition(spWidth+x, spHeight+y); 124 125 126 if(stretchStrategy == NinePatchType.SCALED) 127 { 128 sprites[TOP_MID].setScale(xScalingFactor, 1); 129 sprites[MID_LEFT].setScale(1, yScalingFactor); 130 sprites[MID_RIGHT].setScale(1, yScalingFactor); 131 sprites[BOT_MID].setScale(xScalingFactor, 1); 132 133 //The last one 134 sprites[MID_MID].setScale(xScalingFactor, yScalingFactor); 135 } 136 else 137 { 138 sprites[TOP_MID].setTiling(xScalingFactor, 1); 139 sprites[MID_LEFT].setTiling(1, yScalingFactor); 140 sprites[MID_RIGHT].setTiling(1, yScalingFactor); 141 sprites[BOT_MID].setTiling(xScalingFactor, 1); 142 143 //The last one 144 sprites[MID_MID].setTiling(xScalingFactor, yScalingFactor); 145 } 146 147 // uint thresholdWidth = spWidth*2; 148 // uint thresholdHeight = spHeight*2; 149 150 // if(width < thresholdWidth) 151 // { 152 // float sX = (width/2.0)/thresholdWidth; 153 // sprites[TOP_LEFT].setScale(sX, sprites[TOP_LEFT].scaleY); 154 // sprites[TOP_RIGHT].setScale(sX, sprites[TOP_RIGHT].scaleY); 155 156 // sprites[MID_LEFT].setScale(sX, sprites[MID_LEFT].scaleY); 157 // sprites[MID_RIGHT].setScale(sX, sprites[MID_RIGHT].scaleY); 158 159 // sprites[BOT_LEFT].setScale(sX, sprites[BOT_LEFT].scaleY); 160 // sprites[BOT_RIGHT].setScale(sX, sprites[BOT_RIGHT].scaleY); 161 162 // sprites[TOP_MID].setScale(0,0); 163 // sprites[MID_MID].setScale(0,0); 164 // sprites[BOT_MID].setScale(0,0); 165 // } 166 // if(height < thresholdHeight) 167 // { 168 // float sY = (height/2.0)/thresholdHeight; 169 // sprites[TOP_LEFT].setScale(sprites[TOP_LEFT].scaleX, sY); 170 // sprites[TOP_RIGHT].setScale(sprites[TOP_RIGHT].scaleX, sY); 171 172 // sprites[MID_LEFT].setScale(sprites[MID_LEFT].scaleX, sY); 173 // sprites[MID_RIGHT].setScale(sprites[MID_RIGHT].scaleX, sY); 174 175 // sprites[BOT_LEFT].setScale(sprites[BOT_LEFT].scaleX, sY); 176 // sprites[BOT_RIGHT].setScale(sprites[BOT_RIGHT].scaleX, sY); 177 178 // sprites[TOP_MID].setScale(0,0); 179 // sprites[MID_MID].setScale(0,0); 180 // sprites[BOT_MID].setScale(0,0); 181 // } 182 183 uint i = 0; 184 vertices[i++..i*4] = sprites[TOP_LEFT].getVertices(); 185 vertices[i++..i*4] = sprites[TOP_MID].getVertices(); 186 vertices[i++..i*4] = sprites[TOP_RIGHT].getVertices(); 187 vertices[i++..i*4] = sprites[MID_LEFT].getVertices(); 188 vertices[i++..i*4] = sprites[MID_MID].getVertices(); 189 vertices[i++..i*4] = sprites[MID_RIGHT].getVertices(); 190 vertices[i++..i*4] = sprites[BOT_LEFT].getVertices(); 191 vertices[i++..i*4] = sprites[BOT_MID].getVertices(); 192 vertices[i++..i*4] = sprites[BOT_RIGHT].getVertices(); 193 } 194 195 void setTopLeft(uint u1, uint v1, uint u2, uint v2){sprites[TOP_LEFT].setRegion(u1,v1,u2,v2);} 196 void setTopMid(uint u1, uint v1, uint u2, uint v2){sprites[TOP_MID].setRegion(u1,v1,u2,v2);} 197 void setTopRight(uint u1, uint v1, uint u2, uint v2){sprites[TOP_RIGHT].setRegion(u1,v1,u2,v2);} 198 199 200 void setMidLeft (uint u1, uint v1, uint u2, uint v2){sprites[MID_LEFT].setRegion(u1,v1,u2,v2);} 201 void setMidMid (uint u1, uint v1, uint u2, uint v2){sprites[MID_MID].setRegion(u1,v1,u2,v2);} 202 void setMidRight(uint u1, uint v1, uint u2, uint v2){sprites[MID_RIGHT].setRegion(u1,v1,u2,v2);} 203 204 void setBotLeft (uint u1, uint v1, uint u2, uint v2){sprites[BOT_LEFT].setRegion(u1,v1,u2,v2);} 205 void setBotMid (uint u1, uint v1, uint u2, uint v2){sprites[BOT_MID].setRegion(u1,v1,u2,v2);} 206 void setBotRight(uint u1, uint v1, uint u2, uint v2){sprites[BOT_RIGHT].setRegion(u1,v1,u2,v2);} 207 208 209 void setPosition(float x, float y) 210 { 211 this.x = x; 212 this.y = y; 213 updatePosition(); 214 } 215 216 217 void setColor(HipColor color) 218 { 219 int quad = 0; 220 for(int i = 0; i < 9; i++) 221 { 222 quad = cast(int)(i*4); 223 vertices[quad].vColor = color; 224 vertices[quad+1].vColor = color; 225 vertices[quad+2].vColor = color; 226 vertices[quad+3].vColor = color; 227 } 228 } 229 public ref HipSpriteVertex[4*9] getVertices(){return vertices;} 230 231 232 /** 233 * Use this function instead of build for less overhead 234 */ 235 protected void updatePosition() 236 { 237 uint spWidth = sprites[TOP_LEFT].width; 238 uint spHeight = sprites[TOP_LEFT].height; 239 sprites[TOP_LEFT].setPosition(x, y); 240 sprites[TOP_RIGHT].setPosition(x + (width-spWidth), y); 241 sprites[BOT_LEFT].setPosition(x, y + (height-spHeight)); 242 sprites[BOT_RIGHT].setPosition(x + (width-spWidth), y + (height-spHeight)); 243 sprites[TOP_MID].setPosition(x+spWidth, y); 244 sprites[MID_LEFT].setPosition(x, y+spHeight); 245 sprites[MID_RIGHT].setPosition(x+width-spWidth, y+spHeight); 246 sprites[BOT_MID].setPosition(x+spWidth, y + (height-spHeight)); 247 sprites[MID_MID].setPosition(spWidth+x, spHeight+y); 248 249 for(uint i = 0; i < 9; i++) 250 { 251 uint quad = i*4; 252 HipSpriteVertex[] verts = sprites[i].getVertices(); 253 vertices[quad].vPosition = verts[0].vPosition; 254 vertices[quad+1].vPosition = verts[1].vPosition; 255 vertices[quad+2].vPosition = verts[2].vPosition; 256 vertices[quad+3].vPosition = verts[3].vPosition; 257 } 258 } 259 260 261 } 262 263 private enum : ubyte 264 { 265 TOP_LEFT = 0, 266 TOP_MID, 267 TOP_RIGHT, 268 269 MID_LEFT, 270 MID_MID, 271 MID_RIGHT, 272 273 BOT_LEFT, 274 BOT_MID, 275 BOT_RIGHT 276 }